<!--
 * @Author: 小花
 * @Date: 2022-05-24 22:11:04
 * @LastEditors: 小花
 * @LastEditTime: 2022-05-28 19:56:43
 * @FilePath: /permission_client/src/views/RoleView.vue
 * @Description: 角色管理
-->
<template>
  <el-button type="primary" @click="openAddRoleDialog">
    <font-awesome-icon icon="user-plus" />添加角色
  </el-button>
  <el-button-group>
    <el-button type="primary" @click="setTableLayout('auto')">自动</el-button>
    <el-button type="primary" @click="setTableLayout('fixed')">固定</el-button>
  </el-button-group>
  <el-table ref="multipleTableRef" :data="filterRoleList" :table-layout="tableLayout"
    :header-cell-style="{ background: '#eef1f6', color: '#606266' }" border style="width: 100%">
    <el-table-column type="index" width="55" />
    <el-table-column prop="roleName" align="center" label="角色名称" />
    <el-table-column prop="roleCode" align="center" label="角色编码" />
    <el-table-column prop="description" align="center" label="角色描述" />
    <el-table-column prop="createBy" align="center" label="创建者" />
    <el-table-column prop="createTime" align="center" label="创建时间" />
    <el-table-column prop="updateBy" align="center" label="更新者" />
    <el-table-column prop="updateTime" align="center" label="更新时间" />
    <el-table-column fixed="right">
      <template #header>
        <el-input v-model="tableSearchValue" size="small" placeholder="搜索用户名" />
      </template>
      <template #default="scope">
        <div class="rightFixed">
          <el-link type="primary" :underline="false">用户</el-link>
          <el-dropdown>
            <span class="el-dropdown-link">
              更多
              <font-awesome-icon icon="chevron-down" />
            </span>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item @click="openAuthorizationDialog(scope.row)">
                  授权
                </el-dropdown-item>
                <el-dropdown-item>
                  编辑
                </el-dropdown-item>
                <el-dropdown-item>
                  删除
                </el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </div>
      </template>
    </el-table-column>
  </el-table>
  <el-pagination style="display: flex;justify-content: center;margin: 1rem 0;
  align-items: center;" @size-change="(val: number) => pagination.pageSize = val"
    @current-change="(val: number) => pagination.currentPage = val" :current-page="pagination.currentPage"
    :pager-count="pagination.pagerCount" :page-sizes="pagination.pageSizes" :page-size="pagination.pageSize"
    :total="pagination.total" background layout="total, sizes, prev, pager, next, jumper">
  </el-pagination>

  <el-dialog v-model="updateRoledialog.dialogFormVisible" :title="updateRoledialog.dialogConfig.title"
    :before-close="updateRoledialogBeforeClose">
    <el-form :model="updateRoledialog.form" :rules="rules" :ref="setRuleFormRef" :label-position="'right'"
      label-width="6rem">
      <el-form-item label="角色名称" prop="roleName">
        <el-input v-model="updateRoledialog.form.roleName" placeholder="请输入角色中文名称" />
      </el-form-item>
      <el-form-item label="角色编码" prop="roleCode">
        <el-input v-model="updateRoledialog.form.roleCode" placeholder="请输入角色英文编码" />
      </el-form-item>
      <el-form-item label="角色描述" prop="description">
        <el-input v-model="updateRoledialog.form.description" :autosize="{ minRows: 2 }" maxlength="32" show-word-limit
          type="textarea" placeholder="角色描述" />
      </el-form-item>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="resetForm(updateRoledialog.ruleFormRef)">Cancel</el-button>
        <el-button type="primary" @click="submitForm(updateRoledialog.ruleFormRef)">Confirm</el-button>
      </span>
    </template>
  </el-dialog>

  <el-dialog v-model="authorizationDialog.dialogTreeVisible" :before-close="authorizationDialogBeforeClose"
    :title="authorizationDialog.dialogConfig.title">
    <el-tree :data="menuList" check-strictly show-checkbox node-key="id" :default-checked-keys="defaultCheckedKeys()"
      :default-expand-all="true" :props="defaultProps" :ref="setSelectTreeRef" />
    <template #footer>
      <el-row :gutter="10">
        <el-col :xs="24" :sm="24" :md="2" :lg="2" :xl="2">
          <el-dropdown placement="top">
            <el-button>
              树操作
              <font-awesome-icon icon="angle-up" />
            </el-button>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item @click="setAllTreeSelect(true)">全部勾选
                </el-dropdown-item>
                <el-dropdown-item @click="setAllTreeSelect(false)">全部取消
                </el-dropdown-item>
                <el-dropdown-item @click="setDefaultExpandAll(menuList, true)">展开所有
                </el-dropdown-item>
                <el-dropdown-item @click="setDefaultExpandAll(menuList, false)">合并所有
                </el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </el-col>
        <el-col :xs="24" :sm="24" :md="22" :lg="22" :xl="22">
          <el-button @click="resetTree">取消</el-button>
          <el-button type="primary" plain @click="submitTree(false)">仅保存</el-button>
          <el-button type="primary" @click="submitTree(true)">保存并关闭</el-button>
        </el-col>
      </el-row>
    </template>
  </el-dialog>
</template>

<script lang='ts'>
import { handlerMenu } from '@/model/LoginView'
import { IMenu } from '@/model/MenuView'
import RoleView, { defaultProps, IPermission, IRole } from '@/model/RoleView'
import { pullAllMenuPermission, pullAllRole, pullAllRolePermission, updateRole, updateRolePermission } from '@/request'
import { responseEnum, responseUtil } from '@/request/responseUtil'
import { useStore } from '@/store'
import { DialogBeforeCloseFn, ElMessage, ElTree, FormInstance } from 'element-plus'
import { computed, defineComponent, reactive, toRefs } from 'vue'

export default defineComponent({
  name: 'RoleView',
  setup () {
    const store = useStore()
    const coreData = reactive(new RoleView())

    /**
     * @description: 后端获取所有角色列表
     * @param {*}
     * @return {*}
     */
    const execpullAllRole = async () => {
      const result = await (await pullAllRole()).data as responseUtil<IRole[]>
      if (result.code === responseEnum.OK) {
        coreData.roleList = result.data
        store.roles = coreData.roleList
      } else {
        ElMessage.error(result.msg)
      }
    }

    /**
     * @description: 后端获取所有权限列表
     * @param {*}
     * @return {*}
     */
    const execpullAllRolePermission = async () => {
      const result = await (await pullAllRolePermission()).data as responseUtil<IPermission[]>
      if (result.code === responseEnum.OK) {
        coreData.permissionList = result.data
      }
    }

    /**
     * @description: 后端获取所有菜单权限
     * @param {*}
     * @return {*}
     */
    const execpullAllMenuPermission = async () => {
      const result = await (await pullAllMenuPermission()).data as responseUtil<IMenu[]>
      if (result.code === responseEnum.OK) {
        coreData.originalMenuList = result.data
        coreData.menuList = result.data.filter(it => !it.parentId)
        handlerMenu(result.data.filter(it => it.parentId), coreData.menuList)
      } else if (result.code === responseEnum.FAIL) {
        ElMessage.error(result.msg)
      }
    }

    execpullAllRole()
      .then(() => execpullAllRolePermission())
      .then(() => execpullAllMenuPermission())

    /**
     * @description: 表格分页
     * @param {*} computed
     * @return {*}
     */
    const filterRoleList = computed(() => {
      const filter = coreData.roleList.filter(it => it.roleName.toUpperCase().includes(coreData.tableSearchValue.toUpperCase()))
      return filter.slice((coreData.pagination.currentPage - 1) * coreData.pagination.pageSize, coreData.pagination.currentPage * coreData.pagination.pageSize)
    })

    /**
     * @description: 调整表格布局
     * @param {*} layout
     * @return {*}
     */
    const setTableLayout = (layout: 'auto' | 'fixed') => { coreData.tableLayout = layout }

    /**
     * @description: 打开添加角色对话框
     * @param {*}
     * @return {*}
     */
    const openAddRoleDialog = () => {
      const dialog = coreData.updateRoledialog
      dialog.dialogFormVisible = true
      dialog.dialogConfig.title = '添加角色'
    }

    /**
     * @description: 获取表单对话框ref
     * @param {*} form
     * @return {*}
     */
    const setRuleFormRef = (form: FormInstance) => {
      coreData.updateRoledialog.ruleFormRef = form
    }

    /**
     * @description: 自定义的表单校验规则 -- 验证【角色编码】是否重复使用
     * @param {*} rule rule对象
     * @param {*} value 表单对应值
     * @param {*} callback 通过与否回调
     * @return {*}
     */
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const checkRoleCode = (rule: any, value: any, callback: any) => {
      if (value) {
        const include = coreData.roleList.map(it => it.roleCode.toUpperCase()).includes(value.toUpperCase())
        if (include) {
          callback(new Error('该值不可用，系统中已存在！'))
        } else {
          callback()
        }
      }
    }

    /**
     * @description: 对话框 表单校验规则
     * @param {*}
     * @return {*}
     */
    const rules = {
      roleName: [
        { required: true, message: '请输入角色名', trigger: 'blur' },
        { min: 1, max: 18, message: '账号长度为1-18位', trigger: 'blur' }
      ],
      roleCode: [
        { required: true, message: '请输入角色编码', trigger: 'blur' },
        { min: 1, max: 18, message: '账号长度为1-18位', trigger: 'blur' },
        { validator: checkRoleCode, trigger: 'blur' }
      ],
      description: [
        { min: 0, max: 32, message: '账号长度为0-32位', trigger: 'blur' }
      ]
    }

    /**
     * @description: 重置表单
     * @param {*} formEl
     * @return {*}
     */
    const resetForm = (formEl: FormInstance | undefined) => {
      if (!formEl) return
      formEl.resetFields()
    }

    /**
     * @description: 表单对话框 关闭前的操作
     * @param {*} done
     * @return {*}
     */
    const updateRoledialogBeforeClose: DialogBeforeCloseFn = (done) => {
      resetForm(coreData.updateRoledialog.ruleFormRef)
      done()
    }

    /**
     * @description: 更新/添加角色对话框 提交前的验证
     * @param {*} formEl
     * @return {*}
     */
    const submitForm = (formEl: FormInstance | undefined) => {
      if (!formEl) return
      formEl.validate((valid) => {
        if (valid) {
          execupdateRole()
        } else {
          console.log('error submit!')
          return false
        }
      })
    }

    /**
     * @description: 更新/添加角色 处理器
     * @param {*}
     * @return {*}
     */
    const execupdateRole = async () => {
      const result = await (await updateRole(coreData.updateRoledialog.form)).data as responseUtil<IRole>
      if (result.code === responseEnum.OK) {
        if (coreData.updateRoledialog.form.id) {
          // 更新
          coreData.roleList.splice(coreData.roleList.findIndex(it => it.id === coreData.updateRoledialog.form.id), 1, result.data)
        } else {
          // 添加
          coreData.roleList.push(result.data)
        }
        coreData.updateRoledialog.dialogFormVisible = false
        resetForm(coreData.updateRoledialog.ruleFormRef)
        ElMessage.success(result.msg)
      } else {
        ElMessage.error(result.msg)
      }
    }

    // ================================Tree树对话框的相关方法================================

    /**
     * @description: 获取Tree树的ref
     * @param {*} tree
     * @return {*}
     */
    const setSelectTreeRef = (tree: InstanceType<typeof ElTree>) => {
      coreData.authorizationDialog.selectTreeRef = tree
    }

    /**
     * @description: 打开授权对话框
     * @param {*} row 当前授权角色行
     * @return {*}
     */
    const openAuthorizationDialog = (row: IRole) => {
      coreData.authorizationDialog.form = row
      coreData.authorizationDialog.dialogConfig.title = '角色权限配置'
      coreData.authorizationDialog.dialogTreeVisible = true
    }

    /**
     * @description: 根据角色id，查找权限列表中的角色授权信息，并在树中选中
     * @param {*}
     * @return {*}
     */
    const defaultCheckedKeys = () => {
      const roleId = coreData.authorizationDialog.form.id
      return coreData.permissionList.map(it => it.roleId === roleId && it.permissionId)
    }

    /**
     * @description: 设置 展开或合并所有树
     * @param {IMenu[]} data
     * @param {boolean} expanded
     * @return {*}
     */
    const setDefaultExpandAll = (data: IMenu[], expanded: boolean) => {
      data.forEach((el) => {
        coreData.authorizationDialog.selectTreeRef.store.nodesMap[el.id].expanded = expanded
        if (el.children && el.children.length) setDefaultExpandAll(el.children, expanded)
      })
    }

    /**
     * @description: 设置 全选或取消全选所有树
     * @param {boolean} expanded true: 全选，false: 取消全选
     * @return {*}
     */
    const setAllTreeSelect = (expanded: boolean) => {
      if (expanded) {
        const idList = coreData.originalMenuList.map(it => it.id)
        coreData.authorizationDialog.selectTreeRef.setCheckedKeys(idList, false)
      } else {
        coreData.authorizationDialog.selectTreeRef.setCheckedKeys([], false)
      }
    }

    /**
     * @description: 授权对话框关闭前操作
     * @param {*} done
     * @return {*}
     */
    const authorizationDialogBeforeClose: DialogBeforeCloseFn = (done) => {
      resetTree()
      done()
    }

    /**
     * @description: 重置树
     * @param {*}
     * @return {*}
     */
    const resetTree = () => {
      coreData.authorizationDialog.form = {} as IRole
      setAllTreeSelect(false)
      coreData.authorizationDialog.dialogTreeVisible = false
    }

    /**
     * @description: 更新角色授权信息 处理器
     * @param {boolean} closeDialog true: 保存并关闭 false: 仅保存
     * @return {*}
     */
    const submitTree = async (closeDialog: boolean) => {
      const permissionIds = coreData.authorizationDialog.selectTreeRef.getCheckedKeys(false) as string[]
      if (!permissionIds.length) {
        permissionIds.push(coreData.authorizationDialog.form.id)
      }

      const roleId = coreData.authorizationDialog.form.id
      const data = [] as IPermission[]
      permissionIds.forEach(id => {
        data.push({
          roleId,
          permissionId: id
        })
      })
      const result = await (await updateRolePermission(data)).data as responseUtil
      if (result.code === responseEnum.OK) {
        coreData.permissionList.splice(coreData.permissionList.findIndex(it => it.roleId === coreData.authorizationDialog.form.id), 1)
        coreData.permissionList.push({ ...result.data })
        ElMessage.success(result.msg)
      } else {
        ElMessage.error(result.msg)
      }
      closeDialog && (coreData.authorizationDialog.dialogTreeVisible = false)
    }

    return {
      ...toRefs(coreData),
      filterRoleList,
      rules,
      defaultProps,
      setTableLayout,
      updateRoledialogBeforeClose,
      openAddRoleDialog,
      setRuleFormRef,
      resetForm,
      submitForm,
      execupdateRole,
      openAuthorizationDialog,
      setDefaultExpandAll,
      setSelectTreeRef,
      setAllTreeSelect,
      resetTree,
      submitTree,
      authorizationDialogBeforeClose,
      defaultCheckedKeys
    }
  }
})
</script>

<style lang='scss' scoped>
.el-button-group {
  width: 100%;
  display: flex;
  justify-content: flex-end;
  margin: 0.5rem 0;
}

.el-dropdown-link {
  cursor: pointer;
  color: var(--el-color-primary);
  display: flex;
  align-items: center;
}

.rightFixed {
  display: flex;
  align-items: center;

  .el-link {
    margin-right: 1rem;
  }
}
</style>
